/*
类的基本定义与使用
*/

class Greeter {
    // 声明属性
    message: string

    // 构造方法
    constructor(message: string) {
        this.message = message
    }

    // 一般方法
    greet(): string {
        return 'Hello ' + this.message
    }
}

// 创建类的实例
const greeter = new Greeter('world')
// 调用实例的方法
console.log(greeter.greet())

/*
类的继承
*/

// class Animal {
//     run(distance: number) {
//         console.log(`Animal run ${distance}m`)
//     }
// }
//
// class Dog extends Animal {
//     cry() {
//         console.log('wang! wang!')
//     }
// }
//
// const dog = new Dog()
// dog.cry()
// dog.run(100) // 可以调用从父中继承得到的方法


// class Animal {
//     name: string
//
//     constructor(name: string) {
//         this.name = name
//     }
//
//     run(distance: number = 0) {
//         console.log(`${this.name} run ${distance}m`)
//     }
//
// }
//
// class Snake extends Animal {
//     constructor(name: string) {
//         // 调用父类型构造方法
//         super(name)
//     }
//
//     // 重写父类型的方法
//     run(distance: number = 5) {
//         console.log('sliding...')
//         super.run(distance)
//     }
// }
//
// class Horse extends Animal {
//     constructor(name: string) {
//         // 调用父类型构造方法
//         super(name)
//     }
//
//     // 重写父类型的方法
//     run(distance: number = 50) {
//         console.log('dashing...')
//         // 调用父类型的一般方法
//         super.run(distance)
//     }
//
//     xxx() {
//         console.log('xxx()')
//     }
// }
//
// const snake = new Snake('sn')
// snake.run()
//
// const horse = new Horse('ho')
// horse.run()
//
// // 父类型引用指向子类型的实例 ==> 多态
// const tom: Animal = new Horse('ho22')
// // @ts-ignore
// tom.run()
//
// /* 如果子类型没有扩展的方法, 可以让子类型引用指向父类型的实例 */
// // @ts-ignore
// const tom3: Snake = new Animal('tom3')
// tom3.run()
// /* 如果子类型有扩展的方法, 不能让子类型引用指向父类型的实例 */
// // const tom2: Horse = new Animal('tom2')
// // tom2.run()
//
//

/*
访问修饰符: 用来描述类内部的属性/方法的可访问性
  public: 默认值, 公开的外部也可以访问
  private: 只能类内部可以访问
  protected: 类内部和子类可以访问
*/

class Animal {
    public name: string

    public constructor(name: string) {
        this.name = name
    }

    public run(distance: number = 0) {
        console.log(`${this.name} run ${distance}m`)
    }
}

class Person extends Animal {
    private age: number = 18
    protected sex: string = '男'

    run(distance: number = 5) {
        console.log('Person jumping...')
        super.run(distance)
    }
}

class Student extends Person {
    run(distance: number = 6) {
        console.log('Student jumping...')

        console.log(this.sex) // 子类能看到父类中受保护的成员
        // console.log(this.age) //  子类看不到父类中私有的成员

        super.run(distance)
    }
}

console.log(new Person('abc').name) // 公开的可见
// console.log(new Person('abc').sex) // 受保护的不可见
// console.log(new Person('abc').age) //  私有的不可见

class Person1 {
    readonly name: string = 'abc'

    constructor(name: string) {
        this.name = name
    }
}

let john = new Person1('John')

// john.name = 'peter' // error


class Person2 {
    constructor(readonly name: string) {
    }
}

const p = new Person2('jack')
console.log(p.name)


// class Person3 {
//     firstName: string = 'A'
//     lastName: string = 'B'
//
//     get fullName() {
//         return this.firstName + '-' + this.lastName
//     }
//
//     set fullName(value) {
//         const names = value.split('-')
//         this.firstName = names[0]
//         this.lastName = names[1]
//     }
// }
//
// const p1 = new Person3()
// console.log(p1.fullName)
//
// p1.firstName = 'C'
// p1.lastName = 'D'
// console.log(p1.fullName)
//
// p1.fullName = 'E-F'
// console.log(p1.firstName, p1.lastName)
//
// class Person4 {
//     name1: string = 'A'
//     static name2: string = 'B'
// }
//
// console.log(Person4.name2)
// console.log(new Person4().name1)

/*
抽象类
  不能创建实例对象, 只有实现类才能创建实例
  可以包含未实现的抽象方法
*/

abstract class Animal2 {

    abstract cry()

    run() {
        console.log('run()')
    }
}

class Dog extends Animal2 {
    cry() {
        console.log(' Dog cry()')
    }
}

const dog = new Dog()
dog.cry()
dog.run()
